package com.admin.system.service.impl;


import cn.hutool.core.util.StrUtil;
import com.admin.model.base.PageResult;
import com.admin.model.dto.RoleDto;
import com.admin.model.dto.UserDto;
import com.admin.model.pojo.Menu;
import com.admin.model.pojo.Role;
import com.admin.model.pojo.User;
import com.admin.system.dao.CommonDao;
import com.admin.system.dao.RoleDao;
import com.admin.system.dao.UserDao;
import com.admin.system.security.service.UserDetailsServiceImpl;
import com.admin.system.service.RoleService;
import com.admin.system.service.mapstruct.RoleMapper;
import com.admin.system.service.mapstruct.UserMapper;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * (Role)表服务实现类
 *
 * @author makejava
 * @since 2021-01-31 19:58:51
 */
@CacheConfig(cacheNames = "role")
@Service("roleService")
public class RoleServiceImpl extends ServiceImpl<RoleDao, Role> implements RoleService {
    @Resource
    private RoleDao roleDao;
    @Resource
    private RoleMapper roleMapper;
    @Resource
    private UserDao userDao;
    @Resource
    private UserMapper userMapper;
    @Resource
    private CommonDao commonDao;

    //@Cacheable(key = "'roles'+#pageSize", unless = "#pageNum>0")
    @Override
    public PageResult queryAll(RoleDto roleDto, int pageNum, int pageSize, String sort) {
        Page<Object> page = PageHelper.startPage(pageNum, pageSize, StrUtil.toUnderlineCase(sort));
        List<Role> roleList = roleDao.queryAll(roleMapper.toEntity(roleDto));
        return PageResult.builder()
                .total(page.getTotal())
                .rows(roleMapper.toDto(roleList))
                .build();
    }

    @Override
    public RoleDto queryById(Long id) {
        return roleMapper.toDto(roleDao.selectById(id));
    }

    @Override
    public List<UserDto> queryUserByRoleId(Long roleId) {
        List<User> userList = commonDao.queryUserByRoleId(roleId);
        return userMapper.toDto(userList);
    }

    @Override
    public List<LinkedHashMap<String, Object>> findList() {
        List<Role> list = new LambdaQueryChainWrapper<>(roleDao)
                .select(Role::getId, Role::getName).list();
        return list.stream().map(role -> {
                    LinkedHashMap<String, Object> map = new LinkedHashMap<>();
                    map.put("value", role.getId().toString());
                    map.put("label", role.getName());
                    return map;
                }
        ).collect(Collectors.toList());
    }

    //@CacheEvict(key = "'roles'", allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateById(RoleDto roleDto) {
        Role role = roleMapper.toEntity(roleDto);
        int update = roleDao.updateById(role);
        Assert.isTrue(update > 0, "更新失败");
        Optional<Role> optional = new LambdaQueryChainWrapper<>(roleDao)
                .select(Role::getId)
                .eq(Role::getName, role.getName())
                .last("limit 1")
                .oneOpt();
        Assert.isTrue(!optional.isPresent(), "角色名称重复");
        //删除角色授权菜单，重新授权菜单
        List<Menu> menus = role.getMenus();
        if (!CollectionUtils.isEmpty(menus)) {
            roleDao.delAuthMenuByRoleId(role.getId());
            menus.forEach(menu -> roleDao.authRole(role.getId(), menu.getId()));
        }
        //删除所有用户缓存
        UserDetailsServiceImpl.clearCachUserAll();
    }

    //@CacheEvict(key = "'roles'", allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Role create(RoleDto roleDto) {
        Role role = roleMapper.toEntity(roleDto);
        Optional<Role> optional = new LambdaQueryChainWrapper<>(roleDao)
                .select(Role::getId)
                .eq(Role::getName, role.getName())
                .last("limit 1")
                .oneOpt();
        Assert.isTrue(!optional.isPresent(), "角色重复");
        int insert = roleDao.insert(role);
        Assert.isTrue(insert > 0, "创建失败");
        //授权角色菜单
        List<Menu> menus = role.getMenus();
        if (!CollectionUtils.isEmpty(menus)) {
            menus.forEach(menu -> roleDao.authRole(role.getId(), menu.getId()));
        }
        return roleDao.selectById(role.getId());
    }

    //@CacheEvict(key = "'roles'", allEntries = true)
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void deleteByIds(Set<Long> ids) {
        for (Long id : ids) {
            int delete = roleDao.deleteById(id);
            if (delete > 0) {
                //删除角色授权菜单
                roleDao.delAuthMenuByRoleId(id);
                //删除用户授权角色
                userDao.delAuthRoleByRoleId(id);
            }
        }
        //删除所有用户缓存
        UserDetailsServiceImpl.clearCachUserAll();
    }

    @Override
    public List<Menu> queryMenuByRoleId(Long roleId, int type) {
        return roleDao.queryMenuByRoleIdAndType(roleId, type);
    }

    @Override
    public List<Menu> queryMenuByRoleIdsAndTypeNot(List<Long> roleIds, int type) {
        return roleDao.queryMenuByRoleIdsAndTypeNot(roleIds, type);
    }

    @Override
    public List<Menu> queryMenuByRoleIdsAndType(List<Long> roleIds, int type) {
        return roleDao.queryMenuByRoleIdsAndType(roleIds, type);
    }

    @Override
    public List<Menu> queryTopByRoleIdsAndTypeNot(List<Long> roleIds, int type) {
        return null;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void authMenus(Long roleId, List<Long> menuIds) {
        Role role = roleDao.selectById(roleId);
        Assert.notNull(role, "角色不存在");
        menuIds.forEach(menuId -> {
            int i = roleDao.authRole(roleId, menuId);
        });
    }

}